import logging
import os
from bleak import BleakScanner, BleakClient

# 配置logging
log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bleak.log")

# 确保日志目录存在
os.makedirs(os.path.dirname(log_file), exist_ok=True)

# 配置logging，设置同时输出到文件和控制台
logging.basicConfig(
    level=logging.INFO,
    format='%(filename)s:%(lineno)d %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=[
        logging.FileHandler(log_file, encoding="utf-8", mode="w"),
        logging.StreamHandler(),
    ]
)

async def read_characteristic_value(client, char):
    """读取特征值并处理异常"""
    try:
        value = await client.read_gatt_char(char.uuid)
        logging.info(f"    特征值原始数据: {value}")
        
        # 尝试解码为UTF-8字符串
        try:
            decoded_value = value.decode("utf-8")
            logging.info(f"    特征值(UTF-8解码): {decoded_value}")
        except UnicodeDecodeError:
            # 如果UTF-8解码失败，尝试其他常见编码
            try:
                decoded_value = value.decode("latin-1")
                logging.info(f"    特征值(Latin-1解码): {decoded_value}")
            except UnicodeDecodeError:
                logging.info("    特征值无法解码为字符串")
        
        return value
    except Exception as e:
        logging.error(f"    读取特征失败: {e}")
        return None

async def read_all_characteristics(client):
    """读取设备的所有特征值"""
    services = client.services
    for service in services:
        logging.info(f"\n服务UUID: {service}")
        # 服务UUID解析（判断是否为标准服务）
        if service.uuid.startswith("0000") and len(service.uuid) == 36:
            # 提取16位标准UUID
            short_uuid = f"0x{service.uuid[4:8]}"
            logging.info(f"  标准服务UUID: {short_uuid}")
        else:
            logging.info(f"  非标准服务UUID: {service.uuid}")
        
        # 遍历服务下所有特征
        for char in service.characteristics:
            logging.info(f"  特征UUID: {char.uuid}")
            if char.uuid.startswith("0000") and len(char.uuid) == 36:
                short_char_uuid = f"0x{char.uuid[4:8]}"
                logging.info(f"    标准特征UUID: {short_char_uuid}")
            else:
                logging.info(f"    非标准特征UUID: {char.uuid}")
            
            # 打印特征属性
            properties = []
            if "read" in char.properties:
                properties.append("read")
            if "write" in char.properties:
                properties.append("write")
            if "notify" in char.properties:
                properties.append("notify")
            if "indicate" in char.properties:
                properties.append("indicate")
            logging.info(f"    特征属性: {', '.join(properties)}")
            
            # 如果特征可读，则尝试读取其值
            if "read" in char.properties:
                await read_characteristic_value(client, char)
            else:
                logging.info("    特征不可读")
            
            # 打印描述符信息
            for descriptor in char.descriptors:
                logging.info(f"    描述符UUID: {descriptor.uuid}")
                if descriptor.uuid.startswith("0000") and len(descriptor.uuid) == 36:
                    short_desc_uuid = f"0x{descriptor.uuid[4:8]}"
                    logging.info(f"      标准描述符UUID: {short_desc_uuid}")
                else:
                    logging.info(f"      非标准描述符UUID: {descriptor.uuid}")
                
                # 尝试读取描述符值
                try:
                    desc_value = await client.read_gatt_descriptor(descriptor.handle)
                    logging.info(f"      描述符原始数据: {desc_value}")
                    try:
                        desc_decoded = desc_value.decode("utf-8")
                        logging.info(f"      描述符(UTF-8解码): {desc_decoded}")
                    except UnicodeDecodeError:
                        logging.info("      描述符无法解码为字符串")
                except Exception as e:
                    logging.error(f"      读取描述符失败: {e}")

async def read_battery():
    logging.info("开始扫描BLE设备...")
    devices = await BleakScanner.discover(timeout=10, return_adv=True)
    logging.info(f"发现 {len(devices)} 个BLE设备")

    for key, value in devices.items():
        if key not in ("F8:86:08:74:3C:66", ):
            continue
        logging.info(f"找到目标设备: {value}")

        async with BleakClient(key) as client:
            # 检查是否连接成功
            if not client.is_connected:
                logging.error(f"连接失败: {key} {value}")
                return
            logging.info(f"成功连接到设备: {key}")

            # 读取所有特征值
            await read_all_characteristics(client)
    logging.info("扫描和读取特征操作完成")

if __name__ == "__main__":
    try:
        import asyncio
        logging.info("程序启动")
        asyncio.run(read_battery())
    except Exception as e:
        logging.error(f"程序执行出错: {e}", exc_info=True)
    finally:
        logging.info("程序结束")